
		  import com.adobe.images.JPGEncoder;
		  import mx.managers.PopUpManager;
		  import com.fmi.flickr.DetailedPhotoInfoWindow;
		  import mx.core.IFlexDisplayObject;
		  import com.fmi.flickr.FlickrImage;
		  import com.ericfeminella.collections.HashMap;
		  import mx.controls.Image;
		  import mx.validators.EmailValidator;
		  import de.richinternet.utils.Dumper;
		 
			import com.adobe.webapis.flickr.*;
			import com.adobe.webapis.flickr.events.FlickrResultEvent;
			
			import mx.controls.Alert;
			import mx.utils.ObjectUtil;
			import flash.net.*;
			import flash.geom.Rectangle;
			import mx.effects.Sequence;
			
			private static var tagFieldPrompt:String = "Enter a comma-delimited list of tags";
			
			// This regular expression ensures that the user enters at least one tag
			private static var tagFieldPattern:String = "\w+(, ?\w+)*";
			
			// TODO: Check button v Application-a za "enable logging"
			private var dumpEnabled:Boolean = true;
		
			private var service:FlickrService;
			private var frob:String; // store the frob we'll use for authentication
			
			private static var photosPerPage:int = 100;
			private static var maxPhotosRequested:int;
			
			private var url_photoID_map:HashMap = new HashMap();
			
			private var popUpWindow:DetailedPhotoInfoWindow = null;
			
			private var loggedIn:Boolean = false;
			
			[Bindable]
			private var isFormValid:Boolean = false;
			
			private function tagsFocusInHandler():void  {
			  if (tags.text == tagFieldPrompt)  {
		      tags.text = "";
		      tags.setStyle("fontStyle", "normal");
		    }
			}
			
			private function tagsFocusOutHandler():void  {
			  if (tags.text == "")  {
		      tags.text = tagFieldPrompt;
		      tags.setStyle("fontStyle", "italic");
		    }
			}
			
			private function validateSearchForm():void  {
        var maxNumberValidEvent:ValidationResultEvent 
                                  = maxPhotosValidator.validate(null, true);
        var tagsValidEvent:ValidationResultEvent 
                                  = tagsValidator.validate(null, true);
         // Update the formIsValid flag
         isFormValid = (tagsValidEvent.type == ValidationResultEvent.VALID &&
                        maxNumberValidEvent.type == ValidationResultEvent.VALID);
			}
			
			/**
			 * Initialize the application by creating a new instance of
			 * the Flickr api with our application's api key
			 */
			public function initApp():void
			{
			  tags.text = tagFieldPrompt;
			  
				var api_key:String = "YOUR_FLICKR_API_KEY";
				service = new FlickrService( api_key );
				service.secret = "YOUR_FLICKR_SECRET";

				// Check to see if the auth token was stored, and if so
				// check the token to see if a user is logged in and what
				// kind of permission they have
				var flickrCookie:SharedObject = SharedObject.getLocal( "FlickrServiceTest" );
				if ( flickrCookie.data.auth_token ) {
				  info("Found stored token.. trying to auto-login\n");
				
					// Check the token with the service to auto log in the user
					service.addEventListener( FlickrResultEvent.AUTH_CHECK_TOKEN, checkTokenResponse );
					service.auth.checkToken( flickrCookie.data.auth_token );
				}
				
				tags.addEventListener(KeyboardEvent.KEY_DOWN,checkKey);
				maxImages.addEventListener(KeyboardEvent.KEY_DOWN,checkKey);
				tagMode.addEventListener(KeyboardEvent.KEY_DOWN,checkKey);
				
				focusManager.setFocus(maxImages);
				
				this.cnvImageMap.height*=1.70;
				this.cnvImageMap.width*=1.90;//set the size of Image Map
				
				cnvMain.setFocus();
				application.addEventListener(KeyboardEvent.KEY_DOWN, keyHandler); //globally detecting key enter in application

				var event:MouseEvent = new MouseEvent(MouseEvent.CLICK);
				this.MoveCenter_Click(event);//setting the Image map to be Centered

				currentPictureX = cnvImageMap.width/2;
				currentPictureY = cnvImageMap.height/2;
			}
			
			/**
			 * Called if there was a token stored locally in a cookie. Try to
			 * log the user back in based on the token, otherwise clear
			 * the value.
			 */
			private function checkTokenResponse( event:FlickrResultEvent ):void {
			  info("checkTokenResponse: success = " + event.success + "\n");
				if ( event.success ) {
					// Re-use the login logic in getTokenResponse
					getTokenResponse( event );
				} else {
					var flickrCookie:SharedObject = SharedObject.getLocal( "FlickrServiceTest" );
					flickrCookie.clear();
				}
			}
		
			/**
			 * Some methods require authentication, so this is how you
			 * would start the login sequence.  We need to set the secret
			 * assigned to our particular application, and then get
			 * a frob used for authentication.
			 */
			private function startLoginSequence():void {
				service.addEventListener( FlickrResultEvent.AUTH_GET_FROB, getFrobResponse );
				service.auth.getFrob();
			}
			
			/**
			 * When we receive the frob, we need to construct a login link
			 * and open a browser window for the user to log into the flickr
			 * site.  Use the service getLoginURL method to construct a 
			 * login link with the frob we received, and pass along the
			 * permission we'd like to be granted from the user.
			 */
			private function getFrobResponse( event:FlickrResultEvent ):void {
			  info("getFrobResponse: success = " + event.success + "\n");
				
				if ( event.success ) {
					// Have the service construct a login url for us with the
					// authentication frob, and request the user that we'd like
					// to have DELETE access to their data
					frob = String( event.data.frob );
					var auth_url:String = service.getLoginURL( frob, AuthPerm.READ );
					
					// Open a new browser window to authenticate the user
					// and grant our application permission
					navigateToURL( new URLRequest( auth_url ), "_blank" );
										
					// Show the alert saying  they need to authenticate on the 
					// flickr site.  when the alert closes, we need to get the 
					// token then to get their logged-in status
					Alert.show( "This application requires that you authenticate"
								+ " on Flickr.com before proceeding.  Please log in"
								+ " to Flickr in the separate browser window that"
								+ " opened.  After you have successfully logged in,"
								+ " press 'OK' below to continue",
								"Authentication Required",
								Alert.OK | Alert.CANCEL,
								null,
								onCloseAuthWindow );
								
				} else {
				  error("getFrobResponse error code: " + event.data.error.errorCode + "\n");
				  error("getFrobResponse error message: " + event.data.error.errorMessage + "\n");
				}
			}
			
			/**
			 * After the alert closes, if they pressed the OK button we
			 * assume that they logged into Flickr, so try to get their
			 * auth token that we can use throughout the rest of our app
			 */
			private function onCloseAuthWindow( event:* ):void {
				// Only process if they pressed OK
				if ( event.detail == Alert.OK ) {
					// Get their authentication token, and call getTokenResponse
					// when it's available
					service.addEventListener( FlickrResultEvent.AUTH_GET_TOKEN, getTokenResponse );
					service.auth.getToken( frob );	
				}
			}
			
			/**
			 * This completes the login process.  When the user is successfully
			 * authenticated and the application has permission to use their
			 * data, there will be a token that flickr assigns to us.
			 */
			private function getTokenResponse( event:FlickrResultEvent ):void {
			  info("getTokenResponse: success = " + event.success + "\n");
				
				if ( event.success ) {
					var authResult:AuthResult = AuthResult( event.data.auth );
					// dump the object internals for debugging
					info("Authentication result: " + ObjectUtil.toString( authResult ) + "\n");
					
					// Assign the token and permission to the service so that
					// all calls that require authentication have their values
					// populated
					service.token = authResult.token;
					service.permission = authResult.perms;
					
					// Save the token in a shared object so that when the application
					// loads again we can re-authenticate automatically
					var flickrCookie:SharedObject = SharedObject.getLocal( "FlickrServiceTest" );
					flickrCookie.data.auth_token = service.token;
					flickrCookie.flush();
					
					// Update the UI to show the currently logged in username
					username.text = authResult.user.username + " (" + authResult.user.fullname + " )";
					permission.text = service.permission;
					
					info("token: " + service.token + "\n");
					info("perms: " + service.permission + "\n");
					
					// Toggle the login/logout buttons
					login.visible = false;
					logout.visible = true;
					
					loggedIn = true;
				} else {
				  error("getTokenResponse error code: " + event.data.errorCode + "\n");
			    error("getTokenResponse error message: " + event.data.errorMessage + "\n");
				}
			}
			
			/**
			 * Calls the appropriate Flickr method based on the selection
			 * in the method combobox
			 */
			private function searchPhotos():void {
			  if (!loggedIn)  {
			    Alert.show("You must be logged in with at least READ permissions to " + 
			        "search for photos in Flickr", "Login required");
			        return;
			  }
			  validateSearchForm();
			  if (!isFormValid)  {
			    // Either illegal tags argument or a non-number max photos have been specified
			    Alert.show("Make sure all required fields containt valid values!", "Warning");
			    return;
			  }
			  var search_tags:String = tags.text;
			  var tag_mode:String = tagMode.selectedLabel;
				service.addEventListener( FlickrResultEvent.PHOTOS_SEARCH, searchPhotosResult );

				var maxImagesCount:int = Number(maxImages.text);
				var pageCount:int = maxImagesCount/photosPerPage;
				var extraImagesCount:int = maxImagesCount%photosPerPage;
				
				if (extraImagesCount != 0)  {
				  pageCount += 1;
				}
				maxPhotosRequested = maxImagesCount;
				
				for (var i:int = 1; i<=pageCount; i++)  {
				  service.photos.search( "", search_tags, tag_mode, "", null, null, null, null, -1, "", 100, i, "date-posted-desc" ); 
				}
			}
			
			/**
			 * Generically handle the response to a flickr method call - just output
			 * the information in the event to the screen.
			 */
			private function searchPhotosResult( event:FlickrResultEvent ):void {
			  info(event.type +  " success = " + event.success + "\n");
				
				if ( event.success ) {
					var pagedPhotos:PagedPhotoList = event.data.photos as PagedPhotoList;
					
				  var photos:Array = pagedPhotos.photos;
				  
				  var photoCount:int = photos == null ? 0 : photos.length;
				  
				  var maxPageNum:int = maxPhotosRequested/photosPerPage + 1;
				  
				  if (pagedPhotos.page == maxPageNum)  {
				    photoCount = maxPhotosRequested % photosPerPage;
				  }
				  
				  for (var i:int; i<photoCount; i++)  {
				    var photo:Photo = Photo(photos[i]);
            var url:String = processURL(photo.farm, Object(photo.server).toString(), 
                                      photo.id, photo.secret);
            url_photoID_map.put(url, photo.id);
                  
            loadImage(url);
				  }
				  
				} else {
					// Encountered some kind of error on Flickr...
					var e:FlickrError = FlickrError( event.data.error );
					
					error("error code: " + e.errorCode + "\n");
					error("error message: " + e.errorMessage + "\n");
				}
        
			}
			
			private function loadImage(imageURL:String):void  {
        var imageLoader:Loader = new Loader();
        var imageURLReq:URLRequest = new URLRequest(imageURL);

        imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageContentLoadComplete);
        imageLoader.load(imageURLReq);
      }

      private function imageContentLoadComplete(event:Event):void{
        var photoId:String = url_photoID_map.getValue(event.target.url);
        var image:FlickrImage = new FlickrImage(photoId);
        var bitmap:Bitmap = event.currentTarget.content;
        image.source = bitmap;
        
        if (popUpWindow == null)  {
          AddPicture(image);
        }  else  {
          popUpWindow.imgSource = bitmap;
        }
      }
      
      public function popUpWindowClosed():void  {
        popUpWindow = null;
      }
			
			private function getPhotoInfo(id:String):void  {
			  service.addEventListener( FlickrResultEvent.PHOTOS_GET_INFO, getPhotoInfoResult );
			  service.photos.getInfo(id);
			}
			
		private function getPhotoInfoResult(event:FlickrResultEvent):void  {
			  var photo:Photo = event.data.photo;
			  var url:String = processURL(photo.farm, Object(photo.server).toString(), 
                                      photo.id, photo.secret);
			  var title:String = photo.title;
			  var author:String = photo.ownerName;
			  var originalFormat:String = photo.originalFormat;
			  
			  popUpWindow = DetailedPhotoInfoWindow(
			          PopUpManager.createPopUp(this, DetailedPhotoInfoWindow, true));
        popUpWindow.imgTitle = title;
        popUpWindow.title = title;
			  popUpWindow.imgAuthor = author;
			  popUpWindow.imgUrl = url;
			  popUpWindow.app = this;
			  
			  loadImage(url);
			 }
			
			public function copyBitmap(target: DisplayObject, width:int, height:int) : Bitmap  {
        // Create the bitmap data object with the right size.
        var data : BitmapData = new BitmapData(target.width, target.height, true, 0);
        // Draw the target object into the bitmap data.
        data.draw(target);
        // Create a new bitmap object associated with this data.
        var bitmap: Bitmap = new Bitmap(data);
        return bitmap;
      }
			
			private function processURL(farm_id:String, server_id:String, 
			                              photo_id:String, secret:String):String  {
			  var url:String = "http://farm" + farm_id + ".static.flickr.com/"
			                    + server_id + "/" + photo_id + "_" + secret + ".jpg";
			  return url;
			}
			
			/**
			 * Logout the user from the application and update the display
			 */
			private function processLogout():void {
						
				// Configure the service so it looks like the user
				// is logged out
				service.token = "";
				service.permission = AuthPerm.NONE;
				
				loggedIn = false;
				
				// Update the UI to reflect the user being logged out
				login.visible = true;
				username.text = "Not logged in.";
				permission.text = "none";
				logout.visible = false;
				
				// Clear the authentication cookie so we don't auto-login next time
				var flickrCookie:SharedObject = SharedObject.getLocal( "FlickrServiceTest" );
				flickrCookie.clear();
				
				// Display a note about authentication to the user
				Alert.show("The application instance now considers you to be"
					+ " logged out.  However, the application is still"
					+ " authenticated on flickr.com until you remove it from"
					+ " your 'Authentication list' at"
					+ " http://www.flickr.com/s/auth/list.gne",
					"Logout successful",
					Alert.OK );
			}
			
			private function clearImageMap():void  {
			  cnvImageMap.removeAllChildren();
			  resetVariables();
			}
			
			private function resetVariables():void{
				 	nextPictureToBeLoadedNumber = 1;
			  		currentPictureX = cnvMain.width/2 + 550;
			  		currentPictureY = cnvMain.height/2 + 450;
			  		rightTo = 2;
			  		upTo = 3;
			  		leftTo = 5;
			  		downTo = 7;
			  		roundNumber = 1;
			  		moovingY = 30;
			  		moovingX = 30;
			  		shuffleMovingMax = 10;
			  		pictureSize = 20;
			  		addX = moovingX;
			  		addY = 0;
			}
			
			private function info(infoString:String):void  {
			  if (dumpEnabled)  {
			    Dumper.info(infoString);
			  }
			}
			
			private function warning(warningString:String):void  {
			  if (dumpEnabled)  {
			    Dumper.warn(warningString);
			  }
			}
			
			private function error(errorString:String):void  {
			  if (dumpEnabled)  {
			    Dumper.error(errorString);
			  }
			}